using System;
using System.IO;
using System.Collections.Generic;
using Gtk;
using MonsterNet;

namespace MonsterNetWindows
{
	public partial class MNPreferenceDialog : Gtk.Dialog
	{
		private const string klabelPathLabel = @"Path to {0} directory";
		private const int kNoteBookPageGeneral = 0;
		private const int kNoteBookPageLocations = 1;
		private const int kNoteBookPageIgnoreExt = 2;
		private const int kNoteBookPageBackups = 2;
		
		private MNLocation _location;
		private List<string> _extensionsToIgnore;
		private bool _hasChanged;				
		private bool _restoredBackup = false;
		
		public MNLocation Location {
			get {
				return this._location;
			}
			set {
				_location = value;
			}
		}
		
		public bool HasChanged {
			get {
				return this._hasChanged;
			}
		}
		
		public bool RestoredBackup {
			get {
				return this._restoredBackup;
			}
		}
		

		#region Constructor and helpers
		
		public MNPreferenceDialog (MNLocation location, List<string> extensionsToIgnore)
		{
			this.Build ();
			_location = location;
			_extensionsToIgnore = extensionsToIgnore;
			
			//initalise ignore extensions column
			Gtk.TreeViewColumn extColumn = new Gtk.TreeViewColumn ();
			extColumn.Title = @"Extenstion";
			Gtk.CellRendererText extCell = new Gtk.CellRendererText ();
			extColumn.PackStart (extCell, true);
	
			extColumn.AddAttribute (extCell, "text", 0);
			
			treeviewExtensions.AppendColumn (extColumn);
			
			//initialise backup files columns
			Gtk.TreeViewColumn fileColumn = new Gtk.TreeViewColumn ();
			fileColumn.Title = @"Backup";
			Gtk.CellRendererText fileCell = new Gtk.CellRendererText ();
			fileColumn.PackStart (fileCell, true);
			fileColumn.AddAttribute (fileCell, "text", 0);
			
			Gtk.TreeViewColumn dateColumn = new Gtk.TreeViewColumn ();
			dateColumn.Title = @"Date";
			Gtk.CellRendererText dateCell = new Gtk.CellRendererText ();
			dateColumn.PackStart (dateCell, true);
			dateColumn.AddAttribute (dateCell, "text", 1);
			
			treeviewBackups.AppendColumn (fileColumn);
			treeviewBackups.AppendColumn (dateColumn);
			
			
		}
		
		private string LabelPathText() {
			string result = string.Empty;
			
			if(comboboxLocations.ActiveText != null) {
				result = string.Format(klabelPathLabel, comboboxLocations.ActiveText);
			} else {
				result = string.Format(klabelPathLabel, @"LOCATION NOT SET");
			}
			
			return result;
		}
		
		private void LocationToControls ()
		{
			this.comboboxLocations.Active = (int)_location.CurrentLocation;
			//update label
			radiobuttonPathManual.Label = LabelPathText();
			radiobuttonPathFileChooser.Label = radiobuttonPathManual.Label;
			
			checkbuttonDeleteFromPortable.Active = _location.DeleteFromPortable;
			checkbuttonHideIgnore.Active = _location.HideIgnored;
			checkbuttonHidePrivate.Active = _location.HidePrivate;
			checkbuttonRemoveUsername.Active = _location.RemoveUsername;
			
			if (_location.BackupAutoDeleteCount == 0)
			{
				checkbuttonAutoDelete.Active = false;
				entryDeleteAfter.Sensitive = false;
				entryDeleteAfter.Text = "0";
			} else {
				checkbuttonAutoDelete.Active = true;
				entryDeleteAfter.Sensitive = true;
				entryDeleteAfter.Text = _location.BackupAutoDeleteCount.ToString ();
			}
			
			//check to see if this is the first time run.
			if (_location.CurrentLocation != MNFSObjectLocation.NumberOfLocations) {
				//check to see if the paths exist
				if (Directory.Exists (_location.Path)) {
					
					if(_location.ManualPath) {
						radiobuttonPathManual.Active = true;
						entryPath.Text = _location.Path;
						filechooserbuttonPath.Sensitive = false;
					} else {
						radiobuttonPathFileChooser.Active = true;
						filechooserbuttonPath.Title = LabelPathText ();
						filechooserbuttonPath.SetCurrentFolder (_location.Path);
						entryPath.Sensitive = false;
					}
				} else {
					MessageDialog md = new MessageDialog (this,
					                                     DialogFlags.Modal,
					                                     MessageType.Question,
					                                     ButtonsType.Ok,
					                                     string.Format (@"The path: '{0}' does not currently exist. Are all drives mapped and mounted?",
					                                                   _location.Path));
					md.Run ();
					md.Destroy ();
					
					//set the non existing path to manual
					radiobuttonPathManual.Active = true;
					filechooserbuttonPath.Sensitive = false;
					entryPath.Text = _location.Path;
					_location.ManualPath = true;
					notebookSettings.Page = kNoteBookPageLocations;
				}
				if (Directory.Exists (_location.PortablePath)) {
					this.filechooserbuttonPortablePath.SetCurrentFolder (_location.PortablePath);
				} else {
					MessageDialog md = new MessageDialog (this,
					                                     DialogFlags.Modal,
					                                     MessageType.Question,
					                                     ButtonsType.Ok,
					                                     string.Format (@"The portable path: '{0}' does not currently exist. Are all drives mapped and mounted?",
					                                                   _location.PortablePath));
					md.Run ();
					md.Destroy ();
				
					notebookSettings.Page = kNoteBookPageLocations;
				}
			} else {
				notebookSettings.CurrentPage = kNoteBookPageLocations;
			}
		}	
		
		private void ExtensionsToControls()
		{
			Gtk.ListStore extentions = new Gtk.ListStore(typeof(string));
			foreach(string ext in _extensionsToIgnore) {
				extentions.AppendValues(ext);
			}
			treeviewExtensions.Model = extentions;
		}
		
		private void ControlsToLocation ()
		{
			if(radiobuttonPathManual.Active) {
				_location.Path = this.entryPath.Text;
			} else {
				_location.Path = this.filechooserbuttonPath.CurrentFolder;
			}
			
			_location.PortablePath = this.filechooserbuttonPortablePath.CurrentFolder;
			
			_location.CurrentLocation = (MNFSObjectLocation)this.comboboxLocations.Active;
			
			_location.HideIgnored = checkbuttonHideIgnore.Active;
			_location.HidePrivate = checkbuttonHidePrivate.Active;
			_location.DeleteFromPortable = checkbuttonDeleteFromPortable.Active;
			_location.RemoveUsername = checkbuttonRemoveUsername.Active;
			
			int result;
			if (int.TryParse (entryDeleteAfter.Text, out result))
			{
				_location.BackupAutoDeleteCount = result;
			} else {
				
			}
			
		}
		
		private void BackupFilesToControls ()
		{
			entryDeleteAfter.Text = _location.BackupAutoDeleteCount.ToString ();
			
			Gtk.ListStore backups = new Gtk.ListStore (typeof(string), typeof(string));
			
			foreach (KeyValuePair<string, DateTime> kvp in _location.BackupFiles ()) {
				backups.AppendValues (kvp.Key, kvp.Value.ToString());
			}
			treeviewBackups.Model = backups;			
		}
				
		#endregion

		#region events
	
		protected virtual void OnComboboxLocationsChanged (object sender, System.EventArgs e)
		{
			//update path label
			radiobuttonPathManual.Label = LabelPathText();
			radiobuttonPathFileChooser.Label = radiobuttonPathManual.Label;
			
			filechooserbuttonPath.Title = radiobuttonPathManual.Label;
		}
		
		protected virtual void OnResponse (object o, Gtk.ResponseArgs args)
		{
			if (args.ResponseId == Gtk.ResponseType.Ok)
			{
				ControlsToLocation();
			}
		}
		
		protected virtual void OnMapEvent (object o, Gtk.MapEventArgs args)
		{
			LocationToControls ();
			ExtensionsToControls ();
			BackupFilesToControls ();
		}
		
		protected virtual void OnButtonAddClicked (object sender, System.EventArgs e)
		{
			//add the extension to the treeview
			string newExt = entryIgnoreExtension.Text.Trim();
			
			if(newExt != string.Empty) {
				if(!newExt.StartsWith(".")) 
					newExt = string.Concat(".",newExt);
				
				//check to see if the extension is already in the list.
				if(!_extensionsToIgnore.Contains(newExt)) {
					_extensionsToIgnore.Add(newExt);
					ExtensionsToControls();
				}
				entryIgnoreExtension.Text = string.Empty;
				_hasChanged = true;
			}
		}
		
		protected virtual void OnEntryIgnoreExtensionEditingDone (object sender, System.EventArgs e) {
			Console.WriteLine (@"OnEntryIgnoreExtensionEditingDone");
		}
		
		protected virtual void OnCheckbuttonDeleteFromPortableToggled (object sender, System.EventArgs e) {
			_hasChanged = true;
			_location.DeleteFromPortable = checkbuttonDeleteFromPortable.Active;
		}
				
		protected virtual void OnCheckbuttonHideIgnoreToggled (object sender, System.EventArgs e) {
			_hasChanged = true;
			_location.HideIgnored = checkbuttonHideIgnore.Active;
		}
		
		protected virtual void OnCheckbuttonHidePrivateToggled (object sender, System.EventArgs e) {
			_hasChanged = true;
			_location.HidePrivate = checkbuttonHidePrivate.Active;
		}
		
		protected virtual void OnCheckbuttonRemoveUsernameToggled (object sender, System.EventArgs e)
		{
			_hasChanged = true;
			_location.RemoveUsername = checkbuttonRemoveUsername.Active;
		}		
		
		[GLib.ConnectBeforeAttribute]
		protected virtual void OnTreeviewExtensionsButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
		{
			if (args.Event.Button == 3) /* right click */
			{
				Menu m = new Menu();
				MenuItem delete = new MenuItem (@"Delete");
				delete.Activated += new EventHandler (this.DeleteIgnoreFileExtension);				
				m.Add(delete);
				m.ShowAll();
				m.Popup();
			}			
		}

		protected virtual void DeleteIgnoreFileExtension (object sender, System.EventArgs e)
		{
			TreeIter iter = new TreeIter ();
			
			TreePath currentPath;
			TreeViewColumn currentColumn;
			treeviewExtensions.GetCursor (out currentPath, out currentColumn);
			
			if (currentPath != null) {
				if (treeviewExtensions.Model.GetIter (out iter, currentPath)) {
					string ext = (string)treeviewExtensions.Model.GetValue (iter, 0);
					_extensionsToIgnore.Remove (ext);
					ExtensionsToControls ();
					_hasChanged = true;
				} else {
					//no model data found
				}
			} 			
		}
		
		protected virtual void OnCheckbuttonAutoDeleteToggled (object sender, System.EventArgs e)
		{
			_hasChanged = true;
			entryDeleteAfter.Sensitive = checkbuttonAutoDelete.Active;
			if (!checkbuttonAutoDelete.Active) {
				_location.BackupAutoDeleteCount = 0;
				entryDeleteAfter.Text = "0";
			}	
		}	
		
		protected virtual void OnButtonDeleteBackupClicked (object sender, System.EventArgs e)
		{
			//TODO: show confirmation dialog
			
			//delete the selected backup file
			string backupfile = GetCurrentBackupFile ();
			if (backupfile != string.Empty) {
				MessageDialog md = new MessageDialog (this, DialogFlags.Modal, 
					MessageType.Question, ButtonsType.OkCancel, string.Format (@"Delete backup file '{0}'.", backupfile));
				if (md.Run () == (int)Gtk.ResponseType.Ok)
				{
					_location.BackupDelete (backupfile);
					BackupFilesToControls ();
				}
				md.Destroy ();
			}
		}		

		protected virtual void OnButtonRestoreBackupClicked (object sender, System.EventArgs e)
		{
			// restore the selected backup file	
			string backupFile = GetCurrentBackupFile ();
			if (backupFile != string.Empty)
			{
				MessageDialog md = new MessageDialog (this, DialogFlags.DestroyWithParent, 
					MessageType.Question, ButtonsType.OkCancel, string.Format (@"Restore '{0}' and lose any changes made since.", backupFile));
				
				if (md.Run () == (int)Gtk.ResponseType.Ok)
				{
					_location.RestoreBackup (backupFile);
					_hasChanged = true;
					_restoredBackup = true;
				}
				md.Destroy ();
			}
			
		}
		
		private string GetCurrentBackupFile ()
		{
			string backupFile = string.Empty;
			TreeIter iter = new TreeIter ();
			
			TreePath currentPath;
			TreeViewColumn currentColumn;
			treeviewBackups.GetCursor (out currentPath, out currentColumn);
			
			if (currentPath != null) {
				if (treeviewBackups.Model.GetIter (out iter, currentPath)) {
					backupFile = (string)treeviewBackups.Model.GetValue (iter, 0);
				}
			}
			
			return backupFile;
		}
		
		protected virtual void OnRadiobuttonPathToggled (object sender, System.EventArgs e)
		{
			if(radiobuttonPathManual.Active) {
				entryPath.Text = filechooserbuttonPath.CurrentFolder;
				entryPath.Sensitive = true;
				filechooserbuttonPath.Sensitive = false;
				_location.ManualPath = true;
			} else { //radiobuttonPathFileChooser.Active
				if(entryPath.Text != string.Empty && CheckPath(entryPath.Text)) {
					filechooserbuttonPath.SetCurrentFolder(entryPath.Text);
				}
				entryPath.Sensitive = false;
				filechooserbuttonPath.Sensitive = true;
				_location.ManualPath = false;
			}			
		}

		protected virtual void OnEntryPathFocusOutEvent (object o, Gtk.FocusOutEventArgs args)
		{
			//see if the path exists
			if(entryPath.Text != string.Empty && CheckPath(entryPath.Text)) {	
				_hasChanged = true;
				_location.Path = entryPath.Text;
			}			
		}
		
		#endregion			

		/// <summary>
		/// Warn is the path is inaccessible and return false. Otherwise return true.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/> representing a path
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/> True if the path is accessible
		/// </returns>
		private bool CheckPath(string path) {
			if(!System.IO.Directory.Exists(entryPath.Text)) {	
				MessageDialog md = new MessageDialog (this,
				                                     DialogFlags.Modal,
				                                     MessageType.Warning,
				                                     ButtonsType.Ok,
				                                     string.Format (@"The path: '{0}' is inaccessible.",
				                                                   entryPath.Text));
				md.Run ();
				md.Destroy ();			
				return false;
			} else {
				return true;
			}
		}
		
	}
}

